#include <linux/module.h>
#include <linux/kernel.h> /* printk() */
#include <asm/uaccess.h> /* copy_from/to_user */
#include <linux/fs.h> /* file_operations */
#include <linux/miscdevice.h>
#include <linux/mm.h>

MODULE_LICENSE("GPL");
MODULE_AUTHOR("Ryan Welton <Ryan.G.Welton@gmail.com>");
MODULE_DESCRIPTION("Buggered Linux Device for exploitation");
MODULE_VERSION("1.3.3.7");

#define MAX_MAP_SIZE 0x1000

static int fake_device_mmmap(struct file *file, struct vm_area_struct *vma)
{
        int result = 0;
        int size = vma->vm_end - vma->vm_start;

        pr_err("%s\n", __func__);

        if (size <= MAX_MAP_SIZE) {
              printk("Mapping Area of size : 0x%x\n", size);
                result = remap_pfn_range(vma,
                        vma->vm_start,
                        vma->vm_pgoff,
                        size,
                        vma->vm_page_prot);
        } else {
                pr_err("%s: Not enough memory!\n", __func__);
                result = -ENOMEM;
        }

        return result;
}

static struct file_operations mmap_device_ops = {
  .owner  = THIS_MODULE,
  .mmap   = fake_device_mmmap,
};

static struct miscdevice vuln_device = {
        minor: MISC_DYNAMIC_MINOR,
        name: "special_device_mapper",
        fops: &mmap_device_ops,
        mode: 777
};

static int __init mod_begin(void)
{
   int ret;
   ret = misc_register(&vuln_device);
   if(ret)
     printk("Failed to register misc device");
   else
     printk("Module successfully loaded");

   return ret;//A non 0 return means init_module failed; module can't be loaded.
}

static void __exit mod_exit(void)
{
  int ret = misc_deregister(&vuln_device);
  if(ret)
    printk("There was an error unregistering device");
}

module_init(mod_begin);
module_exit(mod_exit);
